package com.kc.sjwh.other;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.support.SqlSessionDaoSupport;
import org.springframework.beans.factory.annotation.Autowired;

import com.github.pagehelper.PageHelper;

/**
 * DAO基类
 * date: 2017年5月10日
 * @author zhangGuihua(hua7381@163.com)
 */
public class BaseDao<T> extends SqlSessionDaoSupport {
	@Autowired
	protected SqlSessionTemplate templ;
	@Autowired
	public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
		super.setSqlSessionFactory(sqlSessionFactory);
	}
	
	/**
	 * 分页查询
	 * @param p
	 * @return
	 */
	public Page<T> getPage(QueryParam p) {
		return getPage("get", p);
	}
	
	/**
	 * 分页查询
	 * @param sqlId
	 * @param p
	 * @return
	 */
	public Page<T> getPage(String sqlId, QueryParam p) {
		PageHelper.startPage(p.getPageNum(), p.getPageSize());
		List<T> list = templ.selectList(getStatement(sqlId), p);
		List<T> list2 = new ArrayList<T>();
		for(int i=0; i<list.size(); i++) {
			list2.add(list.get(i));
		}
		
		com.github.pagehelper.Page pg = (com.github.pagehelper.Page)list;
		
		//转为本地[分页结果]对象
		Page<T> page = new Page<T>();
		page.setList(list2);
		page.setTotal(pg.getTotal());
		page.setPageSize(pg.getPageSize());
		page.setPageNum(pg.getPageNum());
		page.setPages(pg.getPages());
		return page;
	}
	
	/**
	 * 查询单个对象
	 * @param p
	 * @return
	 */
	public T getOne(QueryParam p) {
		return getOne("get", p);
	}
	
	/**
	 * 查询单个对象
	 * @param sqlId
	 * @param p
	 * @return
	 */
	public T getOne(String sqlId, QueryParam p) {
		return templ.selectOne(getStatement(sqlId), p);
//		return templ.selectOne(getStatement(sqlId), p.addSqlCondition("rownum=1"));
	}
	
	/**
	 * 查询列表
	 * @param p
	 * @return
	 */
	public List<T> getList(QueryParam p) {
		return getList("get", p);
	}
	
	/**
	 * 查询列表
	 * @param sqlId
	 * @param p
	 * @return
	 */
	public List<T> getList(String sqlId, QueryParam p) {
		return templ.selectList(getStatement(sqlId), p);
	}
	
	/**
	 * 查询数量
	 * @param p
	 * @return
	 */
	public int count(QueryParam p) {
		return count("get", p);
	}
	
	/**
	 * 查询数量
	 * @param sqlId
	 * @param p
	 * @return
	 */
	public int count(String sqlId, QueryParam p) {
		PageHelper.startPage(1, -1);
		List<Object> list = templ.selectList(getStatement(sqlId), p);
		com.github.pagehelper.Page page = (com.github.pagehelper.Page)list;
		int total = (int)page.getTotal();
		return total;
	}
	
	/**
	 * 新增
	 * @param one
	 * @return
	 */
	public int add(T one) {
		return add("add", one);
	}
	
	/**
	 * 新增
	 * @param sqlId
	 * @param one
	 * @return
	 */
	public int add(String sqlId, T one) {
		try {
			return templ.insert(getStatement(sqlId), toInsertParam(one));
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	/**
	 * 修改
	 * @param one
	 * @param priKeys
	 * @return
	 */
	public int update(T one, String... priKeys) {
		return update("update", one, priKeys);
	}
	
	/**
	 * 修改
	 * @param sqlId
	 * @param one
	 * @param priKeys 主键
	 * @return
	 */
	public int update(String sqlId, T one, String... priKeys) {
		try {
			return templ.insert(getStatement(sqlId), toUpdateParam(one, priKeys));
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	/**
	 * 删除
	 * @param priKey 主键
	 * @return
	 */
	public int delete(Object priKey) {
		return delete("delete", priKey);
	}
	
	/**
	 * 删除
	 * @param sqlId
	 * @param pk 主键
	 * @return
	 */
	public int delete(String sqlId, Object pk) {
		return templ.delete(getStatement(sqlId), pk);
	}
	
	protected String getStatement(String sqlId) {
		String name = this.getClass().getName();
		StringBuffer sb = new StringBuffer().append(name).append(".").append(sqlId);
		return sb.toString();
	}
	
	//--------------privates---------------
	/**
	 * 转成插入参数.
	 * @param pojo 实体对象
	 * @return the map
	 */
	private static <T> Map toInsertParam(T pojo) {
		try {
			List<Map> props = new ArrayList<Map>();
			for(Method m : pojo.getClass().getDeclaredMethods()) {
				String n = m.getName();
				if(n.startsWith("get") && !n.equals("getClass")) {
					String field = n.substring(3, n.length()).toLowerCase();
					Object val = m.invoke(pojo);
					if(val != null) {
						if(!("id".equals(field) && "".equals(val))) {
							Map prop = new HashMap();
							prop.put("name", field);
							prop.put("value", val);
							props.add(prop);
						}
					}
				}
			}

			Map res = new HashMap();
			res.put("properties", props);
			return res;
		} catch(Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 转成update参数.
	 * @param pojo 实体对象
	 * @param priKeys 主键名称（如:id,复合主键 情况下可传多个）
	 * @return the map
	 */
	private static <T> Map toUpdateParam(T pojo, String... priKeys) {
		try {
			List<Map> props = new ArrayList<Map>();
			List<Map> pks = new ArrayList<Map>();

			Map resMap = new HashMap();
			resMap.put("properties", props);
			resMap.put("priKeys", pks);
			
			for(Method m : pojo.getClass().getDeclaredMethods()) {
				String n = m.getName();
				if(n.startsWith("get") && !n.equals("getClass")) {
					String field = n.substring(3, n.length()).toLowerCase();
					Object val = m.invoke(pojo);
					
					Map prop = new HashMap();
					prop.put("name", field);
					prop.put("value", val);
					
					if (exist(priKeys, field)) {// 是主键
						if (val == null) {
							throw new Exception("主键值为空");
						} else {
							pks.add(prop);
						}
					} else {// 是要修改的字段
						if (val != null) {
							props.add(prop);
						}
					}
				}
			}

			return resMap;
		} catch(Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 检查是否包含在其中
	 * @param arr
	 * @param v
	 */
	private static Boolean exist(String[] arr, String v) {
		Boolean b = false;
		for (String str : arr) {
			if (str.equals(v)) {
				b = true;
				break;
			}
		}
		return b;
	}
}
